Skip to content

feat(backtest): Tier-1 backtest index + iaf index/list/rank CLI (epic #540 phases 1-2)#543

Merged
MDUYN merged 1 commit into
feature/bundle-format-v2from
feature/iaf-index-cli
May 12, 2026
Merged

feat(backtest): Tier-1 backtest index + iaf index/list/rank CLI (epic #540 phases 1-2)#543
MDUYN merged 1 commit into
feature/bundle-format-v2from
feature/iaf-index-cli

Conversation

@MDUYN
Copy link
Copy Markdown
Collaborator

@MDUYN MDUYN commented May 11, 2026

Stacked on #537 (feature/bundle-format-v2, the epic integration branch). Merge #537 first; this PR then folds cleanly into dev. The diff shown here is just the single gap-closing commit on top of #537.

Closes the remaining Phase 1 + Phase 2 gaps for epic #540 — promotes scalar summary metrics out of every .iafbt bundle into a queryable SQLite index, makes the indexer incremental, and ships the CLI to build / query it.

What's in this commit

Phase 1 — naming gap

  • Backtest.scalar_summary() -> BacktestSummaryMetrics — canonical spec alias for get_backtest_summary().

Phase 2 — incremental indexing

  • SqliteBacktestIndex schema bumped to v2 with two new identity columns: bundle_mtime_ns, bundle_size.
  • New SqliteBacktestIndex.is_up_to_date(bundle_path, mtime_ns, size) — single-row lookup keyed on the bundle path.
  • build_index(..., incremental=True) (default) skips bundles whose mtime+size match the existing row.
  • iaf index --rebuild forces a full reindex (passes incremental=False).

Phase 2 — acceptance benchmark

scripts/bench_540_phase2.py generates synthetic bundles and times the hot paths. Measured on a 2024 MacBook Pro:

step 1,000 bundles 12,500 bundles
build_index (cold) 5.2 s 85.9 s
build_index (incremental, all unchanged) 42 ms 536 ms
list --sort sharpe_ratio --limit 20 9.0 ms 8.3 ms
list --sort sharpe_ratio (full scan) 56.5 ms 707 ms

Index footprint at 12,500 bundles: 2.5 MiB (~0.21 KiB / bundle).

The headline ranking workload (list --limit 20) returns in 8 ms over 12.5k rows — 12× under the 100 ms acceptance target and constant in bundle count.

Storage-layer demo

examples/storage_layer_demo/ is an end-to-end walkthrough: write bundles → build index → iaf list / iaf rankBacktest.open(summary_only=True) → inline backtest report. Runnable with python demo.py.

Tests

  • 4 new tests in tests/cli/test_index_command.py: incremental skip, re-ingest on mtime bump, --rebuild disables incremental, scalar_summary() alias parity.
  • Index suite: 28 / 28 passing.
  • Full suite (after reverting unrelated stale workspace edits): 1714 passed / 0 failed / 42 skipped.

Out of scope (Phase 3, follow-up PRs)

BacktestStore Protocol + LocalDirStore + LocalTieredStore (Tier-2 Parquet datasets + Tier-3 content-addressed chunks) and the FinterionStore adapter are tracked separately under #540. They will land as a stacked series on top of #537.

Closes the remaining Phase 2 gaps for epic #540:

- Backtest.scalar_summary() alias (canonical Phase 1 naming).
- SqliteBacktestIndex tracks bundle_mtime_ns + bundle_size (schema v2);
  is_up_to_date() lets the indexer skip unchanged bundles.
- build_index(..., incremental=True) skips up-to-date bundles by default;
  'iaf index --rebuild' forces a full reindex.
- 4 new tests covering skip, re-ingest on mtime bump, --rebuild, and the
  scalar_summary alias.
- scripts/bench_540_phase2.py: acceptance benchmark. At 12,500 bundles:
  cold build 86s, incremental 536ms, list top-20 in 8.3ms (12x under the
  100ms target), index footprint 2.5 MiB.
- examples/storage_layer_demo/: end-to-end walkthrough of write -> index
  -> list -> rank -> open-with-summary-only, plus inline backtest report.
@MDUYN MDUYN changed the base branch from master to dev May 11, 2026 11:17
@MDUYN MDUYN changed the base branch from dev to feature/bundle-format-v2 May 11, 2026 11:40
@MDUYN MDUYN merged commit 444f94d into feature/bundle-format-v2 May 12, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant